home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / c / bc_pas_1.zip / MVSOUND.ASM < prev    next >
Assembly Source File  |  1992-12-08  |  51KB  |  2,089 lines

  1. ;$Author:   DCODY  $
  2. ;$Date:   08 Dec 1992 16:55:46  $
  3. ;$Header:   X:/sccs/mvsound/mvsound.asv   1.7   08 Dec 1992 16:55:46   DCODY  $
  4. ;$Log:   X:/sccs/mvsound/mvsound.asv  $
  5. ;  
  6. ;     Rev 1.7   08 Dec 1992 16:55:46   DCODY
  7. ;  moved externADDR macros for Borland link.
  8. ;  
  9. ;     Rev 1.6   24 Sep 1992 08:54:22   DCODY
  10. ;  changed MVGetHardware to mvGetHardware
  11. ;  
  12. ;     Rev 1.5   12 Aug 1992 17:13:18   DCODY
  13. ;  made call to mvgethardware use a zero (0) parameter to use the current base.
  14. ;  
  15. ;     Rev 1.4   17 Jul 1992 14:18:22   DCODY
  16. ;  moved TheDMAchannel and TheIRQchannel out to another module. Made the
  17. ;  hardware I/O relocatable. Made initmvsound recallable without ill effects.
  18. ;  
  19. ;     Rev 1.3   09 Jul 1992 10:07:50   DCODY
  20. ;  corrected MV101 bit test and jumps
  21. ;  
  22. ;     Rev 1.2   26 Jun 1992 14:13:48   DCODY
  23. ;  added the parameter to GetHWVersion call
  24. ;  
  25. ;     Rev 1.1   23 Jun 1992 17:06:04   DCODY
  26. ;  PAS2 update
  27. ;  
  28. ;     Rev 1.0   15 Jun 1992 09:43:46   BCRANE
  29. ;  Initial revision.
  30. ;$Logfile:   X:/sccs/mvsound/mvsound.asv  $
  31. ;$Modtimes$
  32. ;$Revision:   1.7  $
  33. ;$Workfile:   mvsound.asm  $ 
  34.  
  35.         page    64,131
  36.     Title    MVSOUND  --  Pro Audio Spectrum Sound Support Code
  37.  
  38. ;   /*\
  39. ;---|*|----====< MVSOUND >====----
  40. ;---|*|
  41. ;---|*|  This module contains the code for supporting PCM I/O.
  42. ;---|*|
  43. ;---|*|  Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
  44. ;---|*|
  45. ;   \*/
  46.  
  47. ;
  48. ; The following set of equates are used to control what routines are compiled
  49. ; by doing this, MVSOUND.ASM can contain all the necessary code in one file,
  50. ; but generate separate, linkable objects with just the necessary code.
  51. ;
  52. ALLOBJS     = 0     ; individual objects are being built
  53. DATAOBJ     = 0     ; data code to be compiled
  54. MISC1OBJ    = 0     ; minimum code needed from the library
  55. MISC2OBJ    = 0     ; other miscellaneous code
  56. PCMOBJ        = 0     ; PCM code to be compiled
  57.  
  58. ifdef BUILDDATA
  59.   DATAOBJ   = 1     ; data code to be compiled
  60. endif
  61.  
  62. ifdef BUILDMISC1
  63.   MISC1OBJ  = 1     ; misc module #1 code to be compiled
  64. endif
  65.  
  66. ifdef BUILDMISC2
  67.   MISC2OBJ  = 1     ; misc module #2 code to be compiled
  68. endif
  69.  
  70. ifdef BUILDPCM
  71.   PCMOBJ    = 1     ; data code to be compiled
  72. endif
  73.  
  74. ifdef BUILDALL
  75.   ALLOBJS   = 1     ; all objects are being built
  76.   DATAOBJ   = 1     ; data code to be compiled
  77.   MISC1OBJ  = 1     ; miscellaneous code to be compiled
  78.   MISC2OBJ  = 1     ; miscellaneous code to be compiled
  79.   PCMOBJ    = 1     ; PCM code to be compiled
  80. endif
  81.  
  82.     .xlist
  83.     include model.inc
  84.         include masm.inc
  85.     include target.inc
  86.     include state.inc
  87.     include common.inc
  88.     .list
  89.  
  90. ;
  91. ; structure for pointing to the above table of DMA addresses
  92. ;
  93.  
  94. dmaaddr struc
  95. _dmach        db    ?    ; DMA channel selected
  96. _dmardstat      db      ?       ; DMA read status
  97. _dmawrcntrl    db    ?    ; DMA write command register
  98. _dmawreq    db    ?    ; DMA write request register
  99. _dmawrsmr    db    ?    ; DMA write single mask register
  100. _dmawrmode    db    ?    ; DMA write mode register
  101. _dmaclear    db    ?    ; DMA clear low/high flip-flop
  102. _dmardtemp    db    ?    ; DMA read temp register
  103. _dmawrclr    db    ?    ; DMA write master clear
  104. _dmaclrmsk    db    ?    ; DMA clear mask register
  105. _dmawrall    db    ?    ; DMA write all mask register bits
  106. dmaaddr ends
  107.  
  108. ;
  109. ;---------------------------========================---------------------------
  110. ;---------------------------====< DATA SECTION >====---------------------------
  111. ;---------------------------========================---------------------------
  112. ;
  113.     externADDR  MVInitStatePtr          ; pointer to the state table init code
  114.     externADDR    mvGetHWVersion        ; returns the hardware bits
  115.  
  116. if MODELSIZE eq 0
  117.     .code
  118. else
  119.     .data
  120. endif
  121.  
  122. if DATAOBJ                              ; include if we are building DATA.OBJ
  123.  
  124. ;
  125. ; These variables are DMA/Buffer control variables
  126. ;
  127. TheIRQMask    db    INT7MSK     ; 8259 interrupt mask
  128.  
  129. TheDMAMode    db    00h        ; 44h for input, 48h for output
  130. LinearPtr    dd    0        ; holds linear address
  131. SegmentedPtr    dd    0        ; holds segmented address (real mode)
  132. DMABuffLength    dw    0        ; DMA Length (0 based) (MUST BE EVEN!)
  133. DMABuffDivides    db    0        ; # of splits in the DMA buffer
  134.  
  135. TheSampleRate    dd    0        ; 3k through 88k
  136. StereoMono    db    0        ; ff for mono, 00 for stereo
  137. PCMDirection    db    0        ; bit mask for the DMA controller
  138. SampleSize    db    0        ; sample size: 0=8,1=12,2=16
  139.  
  140.     public    DMAAutoInit        ; TRUE(0ffh) or FALSE(000h)
  141. DMAAutoInit    db    0ffh        ; to allow auto-init on DMA access
  142.  
  143. UserRoutine     dd      0               ; User Code
  144.  
  145. StatusWord      dw      0               ; Holds current status:
  146. ;                    ;   0 = inactive, available
  147. ;                    ;   1 = currently playing
  148. ;                    ;   2 = currently recording
  149.  
  150. OldIRQRoutine   dd      0               ; holds the original routine
  151.  
  152. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  153. dmamask     equ    bICsampbuff        ; dma mask
  154.  
  155. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  156. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  157. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  158. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  159. TypeOfSetup    db    0        ; polled/dma interrupt masks & stuff..
  160.  
  161.     public    NumberOfInterrupts
  162. NumberOfInterrupts      dw      0       ; number of interrupts that have occured
  163. ;
  164. ; These variables direct our code to the proper DMA channel
  165. ;
  166. OurDMAPageReg    dw    CH1PAGEREG    ; default to DMA channel 1 page reg
  167. OurDMAddress    dw    DMAC1ADDR    ; default to DMA channel 1 address reg
  168.  
  169. ;
  170. ; table of address pointers to the various DMA 2 addresses
  171. ;
  172.         public  DMA1AddrTable
  173. DMA1AddrTable    label    byte
  174.     db    DEFAULTDMA    ; DMA channel selected
  175.         db      DMARDSTAT       ; DMA read status
  176.     db    DMAWRCNTRL    ; DMA write command register
  177.     db    DMAWREQ     ; DMA write request register
  178.     db    DMAWRSMR    ; DMA write single mask register
  179.     db    DMAWRMODE    ; DMA write mode register
  180.     db    DMACLEAR    ; DMA clear low/high flip-flop
  181.     db    DMARDTEMP    ; DMA read temp register
  182.     db    DMAWRCLR    ; DMA write master clear
  183.     db    DMACLRMSK    ; DMA clear mask register
  184.     db    DMAWRALL    ; DMA write all mask register bits
  185. ;
  186. ; table of address pointers to the various DMA 2 addresses
  187. ;
  188.     public    DMA2AddrTable
  189. DMA2AddrTable   label   byte
  190.         db      DEFAULTDMA      ; DMA channel selected
  191.     db    DMA2RDSTAT    ; DMA read status
  192.     db    DMA2WRCNTRL    ; DMA write command register
  193.     db    DMA2WREQ    ; DMA write request register
  194.     db    DMA2WRSMR    ; DMA write single mask register
  195.     db    DMA2WRMODE    ; DMA write mode register
  196.     db    DMA2CLEAR    ; DMA clear low/high flip-flop
  197.     db    DMA2RDTEMP    ; DMA read temp register
  198.     db    DMA2WRCLR    ; DMA write master clear
  199.     db    DMA2CLRMSK    ; DMA clear mask register
  200.     db    DMA2WRALL    ; DMA write all mask register bits
  201.  
  202.     public    DMAPointer
  203. DMAPointer      dw      offset DMA1AddrTable    ; default to channel 1 table
  204. ;
  205. ; working variables
  206. ;
  207. ;
  208.     public    TheIRQMask        ; 8259 interrupt mask
  209.     public    TheDMAMode        ; 55h for input, 59h for output
  210.     public    LinearPtr        ; holds linear address
  211.     public    SegmentedPtr        ; holds segmented address (real mode)
  212.     public    DMABuffLength        ; DMA Length (0 based) (MUST BE EVEN!)
  213.     public    DMABuffDivides        ; # of splits in the DMA buffer
  214.     public    TheSampleRate        ; 3k through 88k
  215.     public    StereoMono        ; ff for mono, 00 for stereo
  216.     public    PCMDirection        ; bit mask for the DMA controller
  217.     public    SampleSize        ; sample size: 0=8,1=12,2=16
  218.     public    DMAAutoInit        ; TRUE/FALSE flag for DMA autoinit bit
  219.     public    UserRoutine        ; User Code
  220.     public    StatusWord        ; Holds current status:
  221.     public    OldIRQRoutine        ; holds the original routine
  222. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  223. dmamask     equ    bICsampbuff        ; dma mask
  224. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  225. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  226. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  227. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  228.     public    TypeOfSetup        ; polled/dma interrupt masks & stuff..
  229.     public    NumberOfInterrupts    ; number of interrupts that have occured
  230.     public    OurDMAPageReg        ; default to DMA channel 1 page reg
  231.     public    OurDMAddress        ; default to DMA channel 1 address reg
  232.  
  233. else    ; not building DATA.OBJ, declare all publics
  234.  
  235.     extrn    DMAPointer    :word    ; pointer to the DMA address table
  236.     extrn    DMA1AddrTable    :byte    ; 1st DMA controller table
  237.     extrn    DMA2AddrTable    :byte    ; 2nd DMA controller table
  238.     extrn    TheIRQMask    :byte    ; 8259 interrupt mask
  239.     extrn    TheDMAMode    :byte    ; 55h for input, 59h for output
  240.     extrn    LinearPtr    :dword    ; holds linear address
  241.     extrn    SegmentedPtr    :dword    ; holds segmented address (real mode)
  242.     extrn    DMABuffLength    :word    ; DMA Length (0 based) (MUST BE EVEN!)
  243.     extrn    DMABuffDivides    :byte    ; # of splits in the DMA buffer
  244.     extrn    TheSampleRate    :dword    ; 3k through 88k
  245.     extrn    StereoMono    :byte    ; ff for mono, 00 for stereo
  246.     extrn    PCMDirection    :byte    ; bit mask for the DMA controller
  247.     extrn    SampleSize    :byte    ; sample size: 0=8,1=12,2=16
  248.     extrn    DMAAutoInit    :byte    ; TRUE/FALSE flag for DMA autoinit bit
  249.     extrn    UserRoutine    :dword    ; User Code
  250.     extrn    StatusWord    :word    ; Holds current status:
  251.     extrn    OldIRQRoutine    :dword    ; holds the original routine
  252.     extrn    TypeOfSetup    :byte    ; polled/dma interrupt masks & stuff..
  253.     extrn    NumberOfInterrupts:word ; number of interrupts that have occured
  254.     extrn    OurDMAPageReg    :word    ; default to DMA channel 1 page reg
  255.     extrn    OurDMAddress    :word    ; default to DMA channel 1 address reg
  256.  
  257.  
  258. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  259. dmamask     equ    bICsampbuff        ; dma mask
  260. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  261. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  262. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  263. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  264. SHADOWTABLELEN  equ     28              ; 28 entries in the shadow data table
  265.  
  266. endif
  267.  
  268.     extrn    TheDMAChannel      :byte ; defaults to channel 1
  269.     extrn    TheIRQChannel      :byte ; defaults to IRQ 7
  270.  
  271.         extrn   mvhwShadowPointer :dword; a common variable for all
  272.     extrn    _MVHWVersionBits  :word ; hardware state bits
  273.     extrn    _MVTranslateCode   :word
  274.  
  275.     .code
  276.  
  277. ;
  278. ; TEXT SEGMENT externals for the different modules
  279. ;
  280.  
  281. if PCMOBJ AND (NOT ALLOBJS)        ; added for independent PCMOBJ module
  282.     externADDR    SelectIRQ        ; PCM uses "SelectIRQ"
  283.     externADDR    _unloadirqvector    ; PCM uses "_unloadirqvector"
  284.     externADDR    _getirqoffset        ; PCM uses "_getirqoffset"
  285. endif
  286.  
  287. ;
  288. ;---------------------------========================---------------------------
  289. ;---------------------------====< CODE SECTION >====---------------------------
  290. ;---------------------------========================---------------------------
  291. ;
  292. ;   /*\
  293. ;---|*|
  294. ;---|*|---------------====< Prototypes >====---------------
  295. ;---|*|
  296. ;---|*| void far *DMABuffer(char far *, int, int )
  297. ;---|*|
  298. ;---|*|     Passes in a pointer and length to the buffer.
  299. ;---|*|     Also flushes the buffer. Returns 0 or true DMA buffer ptr.
  300. ;---|*|
  301. ;---|*| int EnablePCMPlay()
  302. ;---|*|
  303. ;---|*|     Sets up the PCM hardware for polled output
  304. ;---|*|
  305. ;---|*| int EnablePCMRecord()
  306. ;---|*|
  307. ;---|*|     Sets up the PCM hardware for polled input
  308. ;---|*|
  309. ;---|*| char huge *FindDMABuffer(char huge *, int )
  310. ;---|*|
  311. ;---|*|     Takes a memory address & return the next 64k boundary
  312. ;---|*|
  313. ;---|*| MVState far *InitMVSound()
  314. ;---|*|
  315. ;---|*|     Initializes the int 2F interface & some global variables.
  316. ;---|*|
  317. ;---|*| int InitPCM()
  318. ;---|*|
  319. ;---|*|     Initializes the PCM code.
  320. ;---|*|
  321. ;---|*| void PausePCM()
  322. ;---|*|
  323. ;---|*|     Temporarily stops the PCM I/O by disabling the timers
  324. ;---|*|
  325. ;---|*| int PCMInfo( long ,int, int, int )
  326. ;---|*|
  327. ;---|*|     Sets up the transfer rate & stereo/mono/compression/data size
  328. ;---|*|
  329. ;---|*| int PCMPlay()
  330. ;---|*|
  331. ;---|*|     Starts the DMA feeding the DAC
  332. ;---|*|
  333. ;---|*| int PCMRecord()
  334. ;---|*|
  335. ;---|*|     Starts the DMA reading the ADC
  336. ;---|*|
  337. ;---|*| void RemovePCM()
  338. ;---|*|
  339. ;---|*|     kills the PCM code.
  340. ;---|*|
  341. ;---|*| void ResumePCM()
  342. ;---|*|
  343. ;---|*|     Restarts the PCM I/O by enabling the timers
  344. ;---|*|
  345. ;---|*| int SelectDMA( int )
  346. ;---|*|
  347. ;---|*|     Selects the DMA channel 1, or 3
  348. ;---|*|
  349. ;---|*| int SelectIRQ( int )
  350. ;---|*|
  351. ;---|*|     Selects the IRQ line for DMA control
  352. ;---|*|
  353. ;---|*| void StopPCM()
  354. ;---|*|
  355. ;---|*|     Turn off the PCM timers, interrupts, and state machine.
  356. ;---|*|
  357. ;---|*| void UserFunc((*long)())
  358. ;---|*|
  359. ;---|*|     Call back routine when Half way buffer is full/empty.
  360. ;---|*|
  361. ;   \*/
  362.  
  363. if PCMOBJ
  364.  
  365. ;   /*\
  366. ;---|*|------====< void far * DMABuffer( char far *, int, int ) >====------
  367. ;---|*|
  368. ;---|*| Passes in a pointer and length to the buffer
  369. ;---|*|
  370. ;---|*| Entry Conditions:
  371. ;---|*|     dParm1 points to DMA buffer
  372. ;---|*|     wParm3 points to the length (wParm3 * 1024 is the total length )
  373. ;---|*|     wParm4 is the # of divisions of the DMA buffer
  374. ;---|*|
  375. ;---|*| Exit Conditions:
  376. ;---|*|     DX:AX = 0 - bad buffer
  377. ;---|*|     DX:AX = returns buffer pointer
  378. ;---|*|
  379. ;   \*/
  380.  
  381.     public    DMABuffer
  382. DMABuffer    proc
  383.         push    bp
  384.     mov    bp,sp
  385.     push    es
  386.     push    di
  387.  
  388.     mov    cx,wParm3        ; get the dma size (4/8/16/32/64)
  389.     cmp    cx,64            ; too high?
  390.     ja    dmabbad         ; yes, bomb out
  391.  
  392.         mov     ax,1024
  393.     cwd
  394.     mul    cx            ; get the length - 1
  395.     dec    ax
  396.     mov    [DMABuffLength],ax    ; and save for later use
  397.  
  398.     les    di,dParm1        ; get the far pointer to the buffer
  399.  
  400.         mov     ax,di
  401.     mov    bx,es            ; convert it to a linear address
  402.     mov    dx,es
  403.     mov    cl,4
  404.     rol    dx,cl
  405.     and    dx,000fh
  406.     shl    bx,cl            ; add offset portion of seg to offset
  407.     add    ax,bx
  408.     jc    dmabbad         ; bad if extends over a 64k boundary
  409.  
  410.     mov    wptr [LinearPtr+0],ax    ; save the linear address
  411.     mov    wptr [LinearPtr+2],dx
  412.     mov    wptr [SegmentedPtr+0],di
  413.     mov    wptr [SegmentedPtr+2],es
  414.  
  415.     mov    bx,wParm4        ; get the # of DMA buffer divisions
  416.     mov    [DMABuffDivides],bl
  417.  
  418.     push    ax            ; save the buffer offset
  419.  
  420.     mov    cx,[DMABuffLength]    ; get the clearing length
  421.         mov     al,80h                  ; PCM silent code
  422.     cld
  423.     rep stosb            ; flush the buffer length...
  424.     stosb                ; + 1
  425.  
  426.     mov    dx,es
  427.         pop     ax                      ; return dx:ax
  428.     jmp    short dmabdone
  429. ;
  430. dmabbad:
  431.     sub    ax,ax
  432.     cwd
  433. ;
  434. dmabdone:
  435.         pop     di
  436.     pop    es
  437.     pop    bp
  438.     ret
  439.  
  440. DMABuffer    endp
  441.  
  442.  
  443. ;   /*\
  444. ;---|*|---------------====< EnablePCMPlay() >====---------------
  445. ;---|*|
  446. ;---|*| Enabled the DAC hardware for polled output (no interrupts)
  447. ;---|*|
  448. ;---|*| Entry Conditions:
  449. ;---|*|     None
  450. ;---|*|
  451. ;---|*| Exit Conditions:
  452. ;---|*|     AX =  0 good start
  453. ;---|*|     AX = -1 not started, problem occured
  454. ;   \*/
  455.  
  456.     public    EnablePCMPlay
  457. EnablePCMPlay    proc
  458.     push    es
  459.  
  460.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  461.     or    ax,wptr [TheSampleRate+2]
  462.     jz    enaPCMPlay_bad          ; zero sample rate, bomb out...
  463.  
  464.     call    FFAR ptr EnablePlaying      ; go for it...
  465.     mov    ax,0
  466.     jmp    short enaPCMPlay_exit
  467. ;
  468. enaPCMPlay_bad:
  469.     mov    ax,-1
  470. ;
  471. enaPCMPlay_exit:
  472.     pop    es
  473.         ret
  474.  
  475. EnablePCMPlay    endp
  476.  
  477.  
  478. ;   /*\
  479. ;---|*|---------------====< EnablePCMRecord() >====---------------
  480. ;---|*|
  481. ;---|*| Enabled the ADC hardware for polled input (no interrupts)
  482. ;---|*|
  483. ;---|*| Entry Conditions:
  484. ;---|*|     None
  485. ;---|*|
  486. ;---|*| Exit Conditions:
  487. ;---|*|     AX =  0 recording has started
  488. ;---|*|     AX = -1 recording did not start
  489. ;---|*|
  490. ;   \*/
  491.  
  492.     public    EnablePCMRecord
  493. EnablePCMRecord proc
  494.         push    es
  495.  
  496.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  497.     or    ax,wptr [TheSampleRate+2]
  498.     jz    enaPCMRec_bad
  499.  
  500.     call    FFAR ptr EnableRecording  ; go for it...
  501.     mov    ax,0
  502.     jmp    short enaPCMRec_exit
  503. ;
  504. enaPCMRec_bad:
  505.     mov    ax,-1
  506. ;
  507. enaPCMRec_exit:
  508.     pop    es
  509.         ret
  510.  
  511. EnablePCMRecord endp
  512.  
  513.  
  514. ;   /*\
  515. ;---|*|------====< char far *FindDMABuffer(char far *,int ) >====------
  516. ;---|*|
  517. ;---|*| Finds the next 64k boundary starting with dParm1 address
  518. ;---|*|
  519. ;---|*| Entry Conditions:
  520. ;---|*|     dParm1 points to a buffer twice the size needed for the DMA
  521. ;---|*|     wParm2 is the size of the DMA buffer (4/8/16/32/64)
  522. ;---|*|
  523. ;---|*| Exit Conditions:
  524. ;---|*|     DX:AX = returns buffer pointer on a 64k boundary
  525. ;---|*|     DX:AX = 0 if boundary wraps beyond 1 meg.
  526. ;---|*|
  527. ;   \*/
  528.  
  529.     public    FindDMABuffer
  530. FindDMABuffer    proc
  531.     push    bp
  532.     mov    bp,sp
  533.  
  534.     sub    ax,ax            ; default to bad...
  535.     cwd
  536.  
  537.         mov     cx,wParm3               ; get the length
  538.     cmp    cx,64            ; 64k buffer requested?
  539.     ja    fdb_exit        ; too high, exit
  540.     jz    fdb_64k         ; yes, special case it...
  541.     cmp    cl,4
  542.     jb    fdb_exit        ; too low, exit
  543.  
  544.     mov    ax,1024         ; calculate the length of the DMA buffer
  545.     mul    cx
  546.     mov    bx,ax            ; bx holds the length
  547.  
  548.     mov    dx,wptr dParm1+2
  549.     mov    ax,dx            ; accumulate the offset in ax
  550.     and    ax,0fffh        ; get the offset portion of the segment
  551.     and    dx,0f000h        ; make DX a 64k segment register
  552.         mov     cl,4
  553.     shl    ax,cl            ; make the segment an offset
  554.     add    ax,wptr dParm1+0    ; accumulate the rest of the offset
  555.     add    bx,ax            ; does the buffer cross a 64k boundary?
  556.     cmc                ; carry set if 64k crossing
  557.     sbb    bx,bx            ; bx = ffff if no crossing, 0 if crossed
  558.     and    ax,bx            ; clear ax if crossed
  559.     not    bx            ; bx = ffff if crossed, 0000 if not
  560.     and    bx,1000h
  561.     add    dx,bx            ; advance dx if we crossed a 64k boundary
  562.     jmp    short fdb_exit
  563. ;
  564. fdb_64k:
  565.     mov    dx,wptr dParm1+2    ; get the segment
  566.         sub     ax,ax                   ; offset is zero
  567.     and    dx,0f000h        ; find the next segment
  568.     add    dx,1000h        ; move to next segment
  569.     jnc    fdb_exit        ; if doesn't wraps past 1 meg, it's good
  570.         cwd                             ; bad, flush it...
  571. ;
  572. fdb_exit:
  573.     pop    bp
  574.     ret
  575.  
  576. FindDMABuffer    endp
  577. ;
  578. endif    ; PCMOBJ
  579. if MISC1OBJ
  580.  
  581. ;
  582. ;   /*\
  583. ;---|*|---------------====< InitMVSound() >====---------------
  584. ;---|*|
  585. ;---|*| Initializes this body of code. It will try to find the int 2F DOS
  586. ;---|*| interface to the MVPROAS device. Once found, the new state table
  587. ;---|*| pointer will be loaded.
  588. ;---|*|
  589. ;---|*| Entry Conditions:
  590. ;---|*|     None
  591. ;---|*|
  592. ;---|*| Exit Conditions:
  593. ;---|*|     DX:AX point to the state table
  594. ;   \*/
  595.  
  596.     public    InitMVSound
  597. InitMVSound    proc
  598.     push    es
  599.     push    di
  600.     mov    ax,ds
  601.     mov    es,ax
  602. ;
  603. ; find the hardware. Should be installed for this to run
  604. ;
  605.     call    MVInitStatePtr        ; initialize the state table ptr
  606.  
  607.     cmp    _MVHWVersionBits,-1    ; initialized yet?
  608.     jnz    @F            ; yes, continue on...
  609.     mov    ax,USE_ACTIVE_ADDR    ; pass in the base address
  610.     push    ax
  611.     call    mvGetHWVersion        ; no, checkout the hardware
  612.     pop    ax
  613.     ;
  614.     @@:
  615.     mov    ax,wptr [mvhwShadowPointer+0]
  616.     mov    dx,wptr [mvhwShadowPointer+2]
  617.  
  618.     pop    di
  619.     pop    es
  620.     ret
  621.  
  622. InitMVSound    endp
  623. ;
  624. endif    ; MISC1OBJ
  625. if    PCMOBJ
  626. ;
  627. ;   /*\
  628. ;---|*|---------------====< InitPCM() >====---------------
  629. ;---|*|
  630. ;---|*| Initializes the PCM code
  631. ;---|*|
  632. ;---|*| Entry Conditions:
  633. ;---|*|     None
  634. ;---|*|
  635. ;---|*| Exit Conditions:
  636. ;---|*|     AX =  Version of this Code
  637. ;   \*/
  638.  
  639.     public    InitPCM
  640. InitPCM proc
  641.     push    es
  642.  
  643.     mov    [TypeOfSetup],polledmask    ; flushes both interrupts
  644.                         ; for upcoming calls
  645.     mov    al,TheDMAChannel        ; initialize the DMA now...
  646.     cbw
  647.     push    ax
  648.     call    FFAR ptr SelectDMA
  649.     pop    ax
  650.  
  651.     mov    al,TheIRQChannel        ; initialize the IRQ now...
  652.     cbw
  653.     push    ax
  654.     call    FFAR ptr SelectIRQ        ; also removes the IRQ
  655.     pop    ax
  656.  
  657.         call    FFAR ptr StopPCM                ; kill the Audio Spectrum board
  658.  
  659.     mov    dx,INTRCTLRST            ; flush any pending PCM irq
  660.     xor    dx,[_MVTranslateCode]        ; xlate the board address
  661.     out    dx,al
  662.  
  663.     sub    ax,ax
  664.     mov    [TypeOfSetup],al        ; unknown type
  665.  
  666.     mov    wptr [UserRoutine+0],ax
  667.     mov    wptr [UserRoutine+2],ax
  668.  
  669.     mov    wptr [LinearPtr+0],ax
  670.     mov    wptr [LinearPtr+2],ax
  671.     mov    wptr [SegmentedPtr+0],ax
  672.         mov     wptr [SegmentedPtr+2],ax
  673.  
  674.     mov    wptr [DMABuffLength],ax
  675.  
  676.     not    al
  677.     mov    [StereoMono],al         ; mono
  678.  
  679.     mov    ax,11025
  680.     cwd
  681.  
  682.     call    FFAR ptr _calcsamplerate    ; setup the default rate
  683.     mov    wptr [TheSampleRate+0],ax
  684.     mov    wptr [TheSampleRate+2],dx
  685.  
  686.     mov    ax,0003h            ; for compatibility, version 00.03
  687.  
  688.     pop    es
  689.     ret
  690.  
  691. InitPCM endp
  692. ;
  693. endif    ; PCMOBJ
  694. if PCMOBJ
  695. ;
  696. ;
  697. ;   /*\
  698. ;---|*|---------------====< PausePCM >====---------------
  699. ;---|*|
  700. ;---|*| Turn off the h/w timer enables to effectively stop pcm temporarily.
  701. ;---|*|
  702. ;---|*| Entry Conditions:
  703. ;---|*|     None
  704. ;---|*|
  705. ;---|*| Exit Conditions:
  706. ;---|*|     Nothing
  707. ;---|*|
  708. ;   \*/
  709. ;
  710.     public    PausePCM
  711. PausePCM    proc
  712.     push    es
  713.     push    di
  714. ;
  715. ; Setup the audio filter sample bits
  716. ;
  717.     les    di,[mvhwShadowPointer]
  718.         mov     dx,AUDIOFILT
  719.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  720.  
  721.         disable
  722.  
  723.         mov     al,es:[di._audiofilt]
  724.     and    al,not bFIsrate        ; flush the enable bits
  725.     mov    es:[di._audiofilt],al
  726.     out    dx,al
  727.  
  728.     enable
  729.  
  730.         pop     di
  731.     pop    es
  732.     ret
  733.  
  734. PausePCM    endp
  735.  
  736. ;
  737. ;   /*\
  738. ;---|*|---------------====< PCMInfo ( long, int, int, int ) >====---------------
  739. ;---|*|
  740. ;---|*| Selects xfer rate & stereo/mono
  741. ;---|*|
  742. ;---|*| Entry Conditions:
  743. ;---|*|     Parm #1 (wParm1, wParm2) is the rate
  744. ;---|*|     Parm #2 (wParm3)         is the stereo(1) or mono (0)
  745. ;---|*|     Parm #3 (wParm4)         is the compression flag
  746. ;---|*|     Parm #4 (wParm5)         is the data size (8/12/16 bits per sample)
  747. ;---|*|
  748. ;---|*| Exit Conditions:
  749. ;---|*|     AX =  0, good data
  750. ;---|*|     AX = -1, bum transfer rate
  751. ;---|*|
  752. ;   \*/
  753.  
  754.     public    PCMInfo
  755. PCMInfo     proc
  756.     push    bp
  757.     mov    bp,sp
  758.  
  759.     mov    al,wParm4+2        ; get the data size
  760.     cbw
  761.     cmp    al,8            ; 8 bit channel?
  762.     jz    @F
  763.  
  764.         inc     ah
  765.     cmp    al,12            ; 12 bit channel
  766.     jz    @F
  767.  
  768.     inc    ah
  769.     cmp    al,16            ; 16 bit channel?
  770.     jnz    pcinf_bad        ; no, bomb out...
  771.     ;
  772.     @@:
  773.     mov    [SampleSize],ah
  774.  
  775.         mov     cx,wParm3               ; get the stereo flag
  776.     shr    cx,1
  777.     jnz    pcinf_bad        ; exit bad if not zero
  778.  
  779.     cmc                ; set for mono, cleared for stereo
  780.     sbb    cx,cx            ; make a full bit mask
  781.     mov    [StereoMono],cl     ; save only valid values
  782.  
  783.         mov     ax,dParm1+0             ; get the sample rate
  784.     mov    dx,dParm1+2
  785.  
  786.     or    cx,cx            ; is it mono?
  787.     jnz    @F            ; yes, skip the doubling
  788.     shl    ax,1            ; no, stereo, so double the sample rate
  789.     adc    dx,dx
  790.     ;
  791.     @@:
  792.     call    FFAR ptr _calcsamplerate
  793.     jc    pcinf_bad
  794.     mov    wptr [TheSampleRate+0],ax
  795.     mov    wptr [TheSampleRate+2],dx
  796.  
  797.     sub    ax,ax
  798.     jmp    short pcinf_exit
  799. ;
  800. pcinf_bad:
  801.     mov    ax,-1
  802. ;
  803. pcinf_exit:
  804.         pop     bp
  805.     ret
  806.  
  807. PCMInfo     endp
  808. ;
  809. ;
  810. ;   /*\
  811. ;---|*|---------------====< PCMPlay() >====---------------
  812. ;---|*|
  813. ;---|*| Starts the DMA feeding the DAC
  814. ;---|*|
  815. ;---|*| Entry Conditions:
  816. ;---|*|     None
  817. ;---|*|
  818. ;---|*| Exit Conditions:
  819. ;---|*|     AX =  0 good start
  820. ;---|*|     AX = -1 not started, problem occured
  821. ;   \*/
  822.  
  823.     public    PCMPlay
  824. PCMPlay proc
  825.     push    es
  826.  
  827.     les    ax,LinearPtr          ; Validate the buffer pointer
  828.     mov    bx,es
  829.     or    ax,bx
  830.     jz    PCMPlay_bad
  831.  
  832.     mov    ax,[DMABuffLength]      ; Validate the buffer count
  833.     or    ax,ax
  834.     jz    PCMPlay_bad
  835.  
  836.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  837.     or    ax,wptr [TheSampleRate+2]
  838.     jz    PCMPlay_bad          ; zero sample rate, bomb out...
  839.  
  840.     call    FFAR ptr StartPlaying      ; go for it...
  841.     sub    ax,ax
  842.     jmp    short PCMPlay_exit
  843. ;
  844. PCMPlay_bad:
  845.     mov    ax,-1
  846. ;
  847. PCMPlay_exit:
  848.     pop    es
  849.         ret
  850.  
  851. PCMPlay endp
  852. ;
  853. ;
  854. ;   /*\
  855. ;---|*|---------------====< PCMRecord() >====---------------
  856. ;---|*|
  857. ;---|*| Starts the DMA reading the ADC
  858. ;---|*|
  859. ;---|*| Entry Conditions:
  860. ;---|*|     None
  861. ;---|*|
  862. ;---|*| Exit Conditions:
  863. ;---|*|     AX =  0 recording has started
  864. ;---|*|     AX = -1 recording did not start
  865. ;---|*|
  866. ;   \*/
  867.  
  868.     public    PCMRecord
  869. PCMRecord proc
  870.         push    es
  871.  
  872.     les    ax,LinearPtr          ; Validate the buffer pointer
  873.     mov    bx,es
  874.     or    ax,bx
  875.     jz    PCMRec_bad
  876.  
  877.     mov    ax,[DMABuffLength]      ; Validate the buffer count
  878.     or    ax,ax
  879.     jz    PCMRec_bad
  880.  
  881.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  882.     or    ax,wptr [TheSampleRate+2]
  883.     jz    PCMRec_bad
  884.  
  885.     call    FFAR ptr StartRecording   ; go for it...
  886.     mov    ax,0
  887.     jmp    short PCMRec_exit
  888. ;
  889. PCMRec_bad:
  890.     mov    ax,-1
  891. ;
  892. PCMRec_exit:
  893.     pop    es
  894.         ret
  895.  
  896. PCMRecord    endp
  897. ;
  898. ;
  899. ;   /*\
  900. ;---|*|---------------====< RemovePCM () >====---------------
  901. ;---|*|
  902. ;---|*| Remove our code from the system
  903. ;---|*|
  904. ;---|*| Entry Conditions:
  905. ;---|*|     None
  906. ;---|*|
  907. ;---|*| Exit Conditions:
  908. ;---|*|     None
  909. ;   \*/
  910.  
  911.     public    RemovePCM
  912. RemovePCM proc
  913.  
  914.     call    FFAR ptr StopPCM        ; kill the Audio Spectrum board
  915.  
  916.         mov     dx,INTRCTLRST                   ; flush any pending PCM irq
  917.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  918.         out     dx,al
  919.  
  920.     call    FFAR ptr _unloadirqvector    ; restore the original vector
  921.  
  922.         ret
  923.  
  924. RemovePCM endp
  925. ;
  926. ;
  927. ;   /*\
  928. ;---|*|---------------====< ResumePCM >====---------------
  929. ;---|*|
  930. ;---|*| Turn on the h/w from making interrupt and DMA requests. This assumes
  931. ;---|*| the hardware has already been setup and is ready to go...
  932. ;---|*|
  933. ;---|*| Entry Conditions:
  934. ;---|*|     None
  935. ;---|*|
  936. ;---|*| Exit Conditions:
  937. ;---|*|     Nothing
  938. ;---|*|
  939. ;   \*/
  940. ;
  941.     public    ResumePCM
  942. ResumePCM    proc
  943.     push    es
  944.     push    di
  945. ;
  946. ; Setup the audio filter sample bits
  947. ;
  948.     les    di,[mvhwShadowPointer]
  949.     call    FFAR ptr _ASloadtimer0
  950.  
  951.         disable
  952.  
  953.         mov     dx,AUDIOFILT
  954.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  955.     mov    al,es:[di._audiofilt]
  956.     or    al,bFIsrate        ; enable sample rate and buffer timers
  957.     mov    es:[di._audiofilt],al
  958.     out    dx,al
  959.  
  960.     enable
  961.  
  962.         pop     di
  963.     pop    es
  964.     ret
  965.  
  966. ResumePCM       endp
  967. ;
  968. ;
  969. ;
  970. ;   /*\
  971. ;---|*|---------------====< SelectDMA( int ) >====---------------
  972. ;---|*|
  973. ;---|*| Selects the DMA channel 0 - 7, excluding 4
  974. ;---|*|
  975. ;---|*| Entry Conditions:
  976. ;---|*|     wParm1 points to DMA number (0, 1, 2, 3, 5, 6, 7 )
  977. ;---|*|
  978. ;---|*| Exit Conditions:
  979. ;---|*|     AX =  0, good buffer, all okay
  980. ;---|*|     AX = -1, good buffer, all okay
  981. ;---|*|
  982. ;   \*/
  983.  
  984.         public  SelectDMA
  985. SelectDMA    proc
  986.     push    bp
  987.     mov    bp,sp
  988.  
  989.         mov     ax,wParm1               ; get the DMA #
  990.  
  991.     and    ax,0111b        ; save the channels
  992.  
  993.         mov     bx,ax                   ; get some of the I/O addreses
  994.     shl    bx,1            ; into DX
  995.     jnz    seldma_02        ; not channel 0, go use it...
  996.     push    sp            ; 8088/86 class machine?
  997.     pop    cx
  998.     cmp    cx,sp
  999.     jnz    seldma_bad        ; yes, can't do channel 0 dma
  1000.     ;
  1001.     seldma_02:
  1002.         mov     dx,cs:[dmatable+bx]
  1003.     or    dx,dx            ; valid entry?
  1004.     jz    seldma_bad        ; no, bomb out...
  1005.  
  1006.         mov     TheDMAChannel,al        ; select the channel.
  1007.     mov    bptr OurDMAPageReg,dh    ; ...the page register,
  1008.     mov    bptr OurDMAddress,dl    ; ...the address register,
  1009.  
  1010.     lea    bx,DMA1AddrTable    ; get the DMA channel addresses
  1011.     cmp    al,4
  1012.     jl    seldma_05
  1013.     lea    bx,DMA2AddrTable    ; get the DMA channel addresses
  1014.     sub    al,4            ; make it zero based
  1015.     ;
  1016.     seldma_05:
  1017.     mov    [bx._dmach],al        ; save the adjusted dma channel #
  1018.     mov    [DMAPointer],bx     ; save the pointer to all DMA addrs
  1019.     sub    ax,ax
  1020.     pop    bp
  1021.     ret
  1022. ;
  1023. seldma_bad:
  1024.     mov    ax,-1
  1025.     pop    bp
  1026.     ret
  1027. ;
  1028. ; dma channels, etc
  1029. ;
  1030. dmatable    label    word
  1031.     dw    (CH0PAGEREG SHL 8) + DMAC0ADDR
  1032.         dw      (CH1PAGEREG SHL 8) + DMAC1ADDR
  1033.     dw    (CH2PAGEREG SHL 8) + DMAC2ADDR
  1034.     dw    (CH3PAGEREG SHL 8) + DMAC3ADDR
  1035.         dw      0
  1036.     dw    (CH5PAGEREG SHL 8) + DMA2C5ADDR
  1037.     dw    (CH6PAGEREG SHL 8) + DMA2C6ADDR
  1038.     dw    (CH7PAGEREG SHL 8) + DMA2C7ADDR
  1039.  
  1040. SelectDMA       endp
  1041.  
  1042. endif    ; PCMOBJ
  1043. if MISC2OBJ
  1044.  
  1045. ;   /*\
  1046. ;---|*|---------------====< SelectIRQ( int ) >====---------------
  1047. ;---|*|
  1048. ;---|*| Selects the IRQ line for DMA control
  1049. ;---|*|
  1050. ;---|*| Entry Conditions:
  1051. ;---|*|     wParm1 points to IRQ number (3,5,6,7)
  1052. ;---|*|
  1053. ;---|*| Exit Conditions:
  1054. ;---|*|     AX =  0, good buffer, all okay
  1055. ;---|*|     AX = -1, bad IRQ #
  1056. ;---|*|
  1057. ;   \*/
  1058.  
  1059.         public  SelectIRQ
  1060. SelectIRQ    proc
  1061.     push    bp
  1062.     mov    bp,sp
  1063.  
  1064.     call    FFAR ptr _unloadirqvector ; attempt to restore original vector
  1065.  
  1066.     sub    ax,ax            ; flush ax for a bad return
  1067.  
  1068.     mov    cx,wParm1        ; get the irq # (2-7,10-12,14-15)
  1069.     and    cl,0fh            ; save only the valid bits
  1070.     mov    bx,01
  1071.     shl    bx,cl
  1072.  
  1073.     and    bx,1001110010111100b    ; save the mask bit only if the irq
  1074.         jz      seirqbad                ; is a valid selection
  1075.  
  1076.     mov    TheIRQChannel,cl    ; save the channel number
  1077.  
  1078.     cmp    cl,8            ; 2nd interrupt controller?
  1079.     jb    @F            ; no, skip
  1080.     xchg    bh,bl
  1081.     ;
  1082.     @@:
  1083.     mov    TheIRQMask,bl
  1084.     call    FFAR ptr _loadirqvector ; load the new vector
  1085.     mov    ax,1
  1086. ;
  1087. seirqbad:
  1088.     dec    ax
  1089.     pop    bp
  1090.     ret
  1091.  
  1092. SelectIRQ       endp
  1093. ;
  1094. endif    ; MISC2OBJ
  1095. if PCMOBJ
  1096.  
  1097. ;
  1098. ;   /*\
  1099. ;---|*|--------------------====< void StopPCM() >====--------------------
  1100. ;---|*|
  1101. ;---|*| Turn off the PCM timers, interrupts, and state machine.
  1102. ;---|*|
  1103. ;---|*| Entry Conditions:
  1104. ;---|*|
  1105. ;---|*| Exit  Conditions:
  1106. ;---|*|
  1107. ;---|*|
  1108. ;   \*/
  1109.  
  1110.     public    StopPCM
  1111. StopPCM proc
  1112.     push    es
  1113.     push    di
  1114.     les    di,[mvhwShadowPointer]
  1115. ;
  1116. ; clear the audio filter sample bits
  1117. ;
  1118.     mov    dx,AUDIOFILT
  1119.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1120.     disable             ; drop dead...
  1121.     mov    al,es:[di._audiofilt]    ; get the state
  1122.     and    al,not (bFIsrate+bFIsbuff) ; flush the sample timer bits
  1123.     mov    es:[di._audiofilt],al    ; save the new state
  1124.     out    dx,al
  1125. ;
  1126. ; clear the PCM enable bit
  1127. ;
  1128.     mov    al,es:[di._crosschannel]; get the current cross channel
  1129.     and    al,not bCCenapcm    ; clear the PCM enable bit
  1130.     or    al,bCCdac
  1131.         mov     dx,CROSSCHANNEL
  1132.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1133.     out    dx,al            ; end to the hardware
  1134.     mov    es:[di._crosschannel],al
  1135. ;
  1136. ; disable the 16 bit stuff
  1137. ;
  1138.     test    [_MVHWVersionBits],bMV101  ; 101 chip?
  1139.     jz    stpc02               ; no, don't touch this...
  1140.     mov    dx,SYSCONFIG2
  1141.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  1142.     in    al,dx
  1143.     and    al,not bSC216bit+bSC212bit ; flush the 16 bit stuff
  1144.     out    dx,al
  1145.     ;
  1146.     stpc02:
  1147. ;
  1148. ; clear the appropriate Interrupt Control Register bit
  1149. ;
  1150.     mov    ah,TypeOfSetup
  1151.     and    ah,bICsamprate+bICsampbuff
  1152.     not    ah
  1153.     mov    dx,INTRCTLR
  1154.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1155.     in    al,dx
  1156.     and    al,ah            ; kill sample timer interrupts
  1157.     out    dx,al
  1158.     mov    es:[di._intrctlr],al
  1159. ;
  1160. ; clear the system interrupt mask only if no other ints are used
  1161. ;
  1162.     test    al,fICintmaskbits XOR (bICsamprate+bICsampbuff)
  1163.     jnz    stpc10
  1164. ;
  1165. ; select the correct IRQ controller, then mask it...
  1166. ;
  1167.     cmp    TheIRQChannel,2     ; Chained IRQ channel?
  1168.     jz    stpc10            ; yes, leave it open...
  1169.  
  1170.         mov     dx,IRQ1MASKREG
  1171.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1172.     jl    stpc05
  1173.     mov    dl,IRQ2MASKREG
  1174.     ;
  1175.     stpc05:
  1176.     in    al,dx
  1177.     or    al,[TheIRQMask]
  1178.     out    dx,al
  1179.     enable                ; start again...
  1180. ;
  1181. stpc10:
  1182.     call    FFAR ptr KillDMA    ; stop the DMA too...
  1183.  
  1184.     mov    [StatusWord],0        ; inactive, available
  1185.  
  1186.     pop    di
  1187.     pop    es
  1188.     ret
  1189.  
  1190. StopPCM endp
  1191.  
  1192. ;
  1193. ;   /*\
  1194. ;---|*|---------------====< UserFunc((*long)()) >====---------------
  1195. ;---|*|
  1196. ;---|*| Call back routine when Half way buffer is full/empty.
  1197. ;---|*|
  1198. ;---|*| Entry Conditions:
  1199. ;---|*|     dParm1 points to the user routine
  1200. ;---|*|
  1201. ;---|*| Exit Conditions:
  1202. ;---|*|     Nothing
  1203. ;---|*|
  1204. ;   \*/
  1205.  
  1206.     public    UserFunc
  1207. UserFunc proc
  1208.     push    bp
  1209.     mov    bp,sp
  1210.  
  1211.         push    es
  1212.  
  1213.     les    ax,dParm1        ; get the routine
  1214.     mov    dx,es
  1215.     or    dx,ax
  1216.     jz    usfu_bad
  1217.  
  1218.     mov    wptr [UserRoutine+0],ax
  1219.     mov    wptr [UserRoutine+2],es
  1220. ;
  1221. usfu_bad:
  1222.     pop    es
  1223.     pop    bp
  1224.     ret
  1225.  
  1226. UserFunc endp
  1227.  
  1228. endif    ; PCMOBJ
  1229.  
  1230. ;
  1231. ;
  1232. ;----------------------------========================--------------------------
  1233. ;----------------------------========================--------------------------
  1234. ;----------------------------========================--------------------------
  1235. ;
  1236. ;
  1237. ;            PPPPPPPP      CCCCCC   MMM     MMM
  1238. ;            PPPPPPPP     CCCCCCC   MMMM    MMMM
  1239. ;            PPP   PPP   CCC        MMMMM   MMMMM
  1240. ;            PPP   PPP   CCC        MMMMMM MMMMMM
  1241. ;            PPPPPPPP    CCC        MMM MMMMM MMM
  1242. ;            PPPPPPPP    CCC        MMM  MMM  MMM
  1243. ;            PPP        CCC        MMM   M     MMM
  1244. ;            PPP        CCC        MMM     MMM
  1245. ;            PPP         CCCCCCC   MMM     MMM
  1246. ;            PPP          CCCCCC   MMM     MMM
  1247. ;
  1248. ;     rrrrr      oooo     uu  uu  tttttt  iiiiii  nn  nn   eeeee   sssss
  1249. ;     rr  rr  oo  oo  uu  uu    tt       ii     nnn nn  ee     ss
  1250. ;     rrrrrr  oo  oo  uu  uu    tt       ii     nnnnnn  eeeeee   ssss
  1251. ;     rr rr     oo  oo  uu  uu    tt       ii     nn nnn  ee         ss
  1252. ;     rr  rr   oooo      uuuuuu   tt     iiiiii  nn  nn   eeeee  sssss
  1253. ;
  1254. ;
  1255. ;
  1256. ;----------------------------========================--------------------------
  1257. ;----------------------------========================--------------------------
  1258. ;----------------------------========================--------------------------
  1259.  
  1260. if PCMOBJ
  1261.  
  1262. ;
  1263. ;----------------------------====< _ASloadtimer0 >====-------------------------
  1264. ;
  1265. ;
  1266. ; Setup the Sample Timer (T0 & square wave output)
  1267. ;
  1268. ;   Entry Conditions:
  1269. ;    ES:DI point to the state table.
  1270. ;   Exit Conditions:
  1271. ;    The timer is loaded with the new sample rate
  1272. ;
  1273.     public    _ASloadtimer0
  1274. _ASloadtimer0    proc
  1275.  
  1276.         mov     al,00110110b            ; 36h Timer 0 & square wave
  1277.     mov    dx,TMRCTLR
  1278.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1279.  
  1280.     pushf
  1281.     cli
  1282.  
  1283.     out    dx,al            ; setup the mode, etc
  1284.         mov     es:[di._tmrctlr],al
  1285.  
  1286.     mov    ax,es:[di._samplerate]    ; pre-calculated & saved in prior code
  1287.     mov    dx,SAMPLERATE
  1288.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1289.     out    dx,al            ; output the timer value
  1290.  
  1291.         pause
  1292.  
  1293.         xchg    ah,al
  1294.     out    dx,al
  1295.  
  1296.         popf
  1297.     ret
  1298.  
  1299. _ASloadtimer0   endp
  1300.  
  1301. ;
  1302. ;----------------------------====< _ASloadtimer1 >====-------------------------
  1303. ;
  1304.         public  _ASloadtimer1
  1305. _ASloadtimer1   proc
  1306.     push    es
  1307.     push    di
  1308.     les    di,[mvhwShadowPointer]
  1309.  
  1310.         push    dx                      ; do not disturb any register
  1311.     push    ax
  1312.  
  1313.         mov     al,01110100b            ; 74h Timer 1 & rate generator
  1314.     mov    dx,TMRCTLR
  1315.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1316.  
  1317.         disable
  1318.  
  1319.         out     dx,al
  1320.     mov    es:[di._tmrctlr],al    ; local timer control register
  1321.  
  1322.     pop    ax
  1323.  
  1324.         mov     dx,SAMPLECNT
  1325.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1326.     mov    es:[di._samplecnt],ax
  1327.  
  1328.         out     dx,al
  1329.         pause
  1330.     xchg    ah,al
  1331.     out    dx,al
  1332.  
  1333.     enable
  1334.  
  1335.     xchg    ah,al
  1336.  
  1337.     pop    dx
  1338.     pop    di
  1339.     pop    es
  1340.     ret
  1341.  
  1342. _ASloadtimer1    endp
  1343. ;
  1344. ;
  1345. ;--------------------------====< _calcsamplerate >====-------------------------
  1346. ;
  1347. ;  Calculate the H/W timer value (internal routine)
  1348. ;
  1349. ; Entry Conditions:
  1350. ;    DX:AX hold the users requested sample rate
  1351. ;
  1352. ; Exit Conditions:
  1353. ;    carry SET if bad value
  1354. ;    No registers modified
  1355. ;
  1356. ;
  1357.     public    _calcsamplerate
  1358. _calcsamplerate proc
  1359.     push    es
  1360.     push    di
  1361.     les    di,[mvhwShadowPointer]
  1362.  
  1363.     push    ax
  1364.     push    bx
  1365.     push    cx
  1366.     push    dx
  1367. ;
  1368. ; make sure sample rate does not exceed 88200
  1369. ;
  1370.         mov     cx,ax                   ; do 32 bit subtraction
  1371.     sub    cx,05888H+1        ; 157C0 is decimal 88200
  1372.     mov    cx,dx            ; too high?
  1373.     sbb    cx,00001H        ;  over 88200 khz is bad
  1374.     jnc    CaSaRa_bad        ; bomb out greater than 88200
  1375. ;
  1376. ; load 1193180 in bx:cx for 32x32 bit division
  1377. ;
  1378.     mov    bx,0012h
  1379.     mov    cx,34dch        ; load bx:cx with 1193180
  1380.  
  1381.     xchg    bx,dx            ; dx:ax = 1193180
  1382.     xchg    cx,ax            ; bx:cx = sample rate
  1383. ;
  1384. ; since we don't have 32x32 bit division, we'll cheat here. No great loss.
  1385. ;
  1386.     or    bx,bx            ; is value over 64k?
  1387.     jz    @F            ; no, continue on...
  1388.     shr    bx,1            ; yes, divide all by 2
  1389.     rcr    cx,1            ; to allow division of 32x16 bits
  1390.     shr    dx,1
  1391.     rcr    ax,1
  1392. ;
  1393. @@:
  1394.     div    cx
  1395.     mov    es:[di._samplerate],ax    ; save just the low order
  1396.     clc
  1397.     jmp    short CaSaRa_exit
  1398. ;
  1399. CaSaRa_bad:
  1400.     stc
  1401. ;
  1402. CaSaRa_exit:
  1403.     pop    dx
  1404.     pop    cx
  1405.     pop    bx
  1406.     pop    ax
  1407.  
  1408.         pop     di
  1409.     pop    es
  1410.     ret
  1411.  
  1412. _calcsamplerate endp
  1413. ;
  1414. ;
  1415. ;----------------------------====< EnableRecording >====-----------------------
  1416. ;
  1417.     public    EnableRecording
  1418. EnableRecording  proc
  1419. ;
  1420. ; Save the type of setup. It contains the interrupt masks needed
  1421. ;
  1422.     mov    [TypeOfSetup],POLLEDINPUT
  1423.     mov    [PCMDirection],0    ; bit 6 is cleared (DAC enable)
  1424. ;
  1425. ; enable the onboard sampling timers, disable interrupts
  1426. ;
  1427.     call    FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
  1428.     mov    StatusWord,2        ; set the global status word
  1429.         ret
  1430.  
  1431. EnableRecording  endp
  1432. ;
  1433. ;
  1434. ;----------------------------====< EnablePlaying >====-------------------------
  1435. ;
  1436.     public    EnablePlaying
  1437. EnablePlaying    proc
  1438. ;
  1439. ; Save the type of setup. It contains the interrupt masks needed
  1440. ;
  1441.     mov    [TypeOfSetup],POLLEDOUTPUT
  1442.         mov     [PCMDirection],bCCdac   ; bit d6 of interrupt control register
  1443. ;
  1444. ; enable the onboard sampling timers, etc.
  1445. ;
  1446.     call    FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
  1447.     mov    StatusWord,1        ; set the global status word
  1448.  
  1449.         ret
  1450.  
  1451. EnablePlaying     endp
  1452. ;
  1453. endif    ; PCMOBJ
  1454. if MISC2OBJ
  1455. ;
  1456. ;---------------------------====< _getirqoffset >====--------------------------
  1457. ;
  1458. ; takes the IRQ # & converts to offset in vector table
  1459. ;
  1460. ;
  1461.     public    _getirqoffset
  1462. _getirqoffset   proc
  1463.         sub     bh,bh
  1464.     shl    bx,1
  1465.     mov    bx,cs:[irqoffsets+bx]
  1466.     ret
  1467.  
  1468. irqoffsets    label    word
  1469.     dw    (8+0)*4         ; IRQ 0 clock timer
  1470.     dw    (8+1)*4         ; IRQ 1 keyboard
  1471.     dw    (8+2)*4         ; IRQ 2 available
  1472.     dw    (8+3)*4         ; IRQ 3 COM2
  1473.     dw    (8+4)*4         ; IRQ 4 COM1
  1474.     dw    (8+5)*4         ; IRQ 5 available
  1475.     dw    (8+6)*4         ; IRQ 6 floppy controller
  1476.     dw    (8+7)*4         ; IRQ 7 LPT
  1477.     dw    (70h+0)*4        ; IRQ 8 real time clock
  1478.     dw    (70h+1)*4        ; IRQ 9 Re-Directed IRQ2
  1479.     dw    (70h+2)*4        ; IRQ a available
  1480.     dw    (70h+3)*4        ; IRQ b available
  1481.     dw    (70h+4)*4        ; IRQ c available
  1482.     dw    (70h+5)*4        ; IRQ d coprocessor
  1483.     dw    (70h+6)*4        ; IRQ e Hard Disk
  1484.     dw    (70h+7)*4        ; IRQ f available
  1485.  
  1486. _getirqoffset   endp
  1487. ;
  1488. endif    ; MISC2OBJ
  1489. if PCMOBJ
  1490. ;
  1491. ;------------------------------====< KillDMA >====-----------------------------
  1492. ;
  1493. ; KillDMA  -- flush our settings
  1494. ;
  1495. ; Entry Conditions:
  1496. ;
  1497. KillDMA proc
  1498.     push    es
  1499.     push    di
  1500.  
  1501.         cmp     StatusWord,0            ; is there any activity?
  1502.     jz    kidm_none
  1503.  
  1504.     mov    di,[DMAPointer]     ; get the DMA pointer
  1505.         sub     dx,dx                   ; clear out the high byte
  1506. ;
  1507. ; mask out the DMA to stop it
  1508. ;
  1509.     disable
  1510.     mov    al,[di._dmach]        ; get the adjusted dma channel #
  1511.         or      al,0100b                ; disable the DMA
  1512.     mov    dl,[di._dmawrsmr]
  1513.     out    dx,al
  1514. ;
  1515. ; remove control on the DRQ line
  1516. ;
  1517.         les     di,[mvhwShadowPointer]
  1518.  
  1519.         mov     al,es:[di._crosschannel]; get the state
  1520.         mov     dx,CROSSCHANNEL
  1521.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1522.     and    al,not bCCdrq        ; clear the DRQ bit
  1523.     out    dx,al
  1524.  
  1525.         mov     es:[di._crosschannel],al; and save the new state
  1526.     enable
  1527. ;
  1528. kidm_none:
  1529.     pop    di
  1530.     pop    es
  1531.     ret
  1532.  
  1533. KillDMA endp
  1534. ;
  1535. endif    ; PCMOBJ
  1536. if PCMOBJ
  1537. ;
  1538. ;------------------------------====< LoadDMA >====-----------------------------
  1539. ;
  1540. ; LoadDMA  -- Load the DMA controller to read/write data to the MV board
  1541. ;
  1542. ; Entry Conditions:
  1543. ;
  1544. ;
  1545.     public    LoadDMA
  1546. LoadDMA proc
  1547.     push    es
  1548.     push    di
  1549.     push    si
  1550.  
  1551.         les     di,[mvhwShadowPointer]
  1552.  
  1553.     mov    si,[DMAPointer]     ; point to the DMA controller table
  1554.     sub    dx,dx            ; clear out the high byte
  1555. ;
  1556. ; kill the dma until all programming is done
  1557. ;
  1558.     mov    al,[si._dmach]        ; get the adjusted dma channel #
  1559.         or      al,0100b                ; causes all DMA to be suspended
  1560.     mov    dl,[si._dmawrsmr]
  1561.     out    dx,al
  1562. ;
  1563. ; program the mode
  1564. ;
  1565.         mov     al,[TheDMAmode]         ; get the app's desired mode
  1566.     or    al,[si._dmach]        ; merge the adjusted dma channel #
  1567.     mov    dl,[si._dmawrmode]
  1568.         out     dx,al
  1569. ;
  1570. ; adjust the address for a 16 bit channel
  1571. ;
  1572.     mov    ax,wptr [LinearPtr+2]    ; get the page #
  1573. ;
  1574. ; setup the page register
  1575. ;
  1576.     mov    dx,[OurDMAPageReg]
  1577.     out    dx,al
  1578.     mov    bl,al
  1579. ;
  1580. ; reset the flip-flop, then output the address, then count
  1581. ;
  1582.     mov    dl,[si._dmaclear]    ; dh is still clear...
  1583.         out     dx,al                   ; flush...
  1584.  
  1585.     mov    ax,wptr [LinearPtr+0]    ; get the low 16 bits
  1586.     cmp    si,offset DMA1AddrTable ; 1st DMA controller?
  1587.     jz    @F            ; yes, continue on...
  1588.     shr    bl,1            ; no, divide the buffer in half
  1589.     rcr    ax,1            ; by shifting 17 bits
  1590.     ;
  1591.     @@:
  1592.     mov    dx,[OurDMAddress]
  1593.     out    dx,al
  1594.     pause
  1595.     xchg    ah,al
  1596.     out    dx,al
  1597.  
  1598.     mov    ax,[DMABuffLength]
  1599.     cmp    si,offset DMA1AddrTable ; is this the 2nd dma controller?
  1600.     jz    lodma03         ; no, use the full length
  1601.     shr    ax,1
  1602.         inc     dx                      ; move to next port address
  1603.     ;
  1604.     lodma03:
  1605.     inc    dx            ; move to next port address
  1606.     out    dx,al
  1607.     pause
  1608.     xchg    ah,al
  1609.     out    dx,al
  1610. ;
  1611. ; before we enable the DMA, let's make sure the DRQ is controlled, not floating
  1612. ;
  1613.     mov    al,es:[di._crosschannel]; get the state
  1614.         mov     dx,CROSSCHANNEL
  1615.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1616.     or    al,bCCdrq        ; set the DRQ bit to control it
  1617.     out    dx,al
  1618.     mov    es:[di._crosschannel],al; and save the new state
  1619. ;
  1620. ; re-enable the dma now that all programming is done
  1621. ;
  1622.     mov    al,[si._dmach]        ; get the adjusted dma channel #
  1623.         sub     dx,dx                   ; clear dh
  1624.     mov    dl,[si._dmawrsmr]
  1625.     out    dx,al            ; & let'er loose (not moving though...)
  1626. ;
  1627. ; all done, return home...
  1628. ;
  1629.     pop    si
  1630.     pop    di
  1631.     pop    es
  1632.     ret
  1633.  
  1634. LoadDMA endp
  1635. ;
  1636. endif    ; PCMOBJ
  1637. if MISC2OBJ
  1638. ;
  1639. ;--------------------------====< _loadirqvector >====--------------------------
  1640. ;
  1641. ; Restore the original vector
  1642. ;
  1643. ; Entry Conditions:
  1644. ;
  1645. ; Exit Conditions:
  1646. ;     Nothing
  1647.  
  1648.     public    _loadirqvector
  1649. _loadirqvector  proc
  1650.     push    es
  1651.  
  1652.         les     ax,OldIRQRoutine
  1653.     mov    bx,es
  1654.     or    bx,ax
  1655.     jnz    @F
  1656.  
  1657.     lea    ax,OurIntVector
  1658.     mov    dx,cs
  1659.  
  1660.     mov    bl,[TheIRQChannel]
  1661.     call    FFAR ptr _getirqoffset
  1662.  
  1663.     push    ds
  1664.     sub    cx,cx
  1665.     mov    ds,cx
  1666.  
  1667.     disable
  1668.     xchg    ds:[bx+0],ax
  1669.     xchg    ds:[bx+2],dx
  1670.     enable
  1671.  
  1672.     pop    ds
  1673.  
  1674.     mov    wptr [OldIRQRoutine+0],ax
  1675.     mov    wptr [OldIRQRoutine+2],dx
  1676. ;
  1677. @@:
  1678.     pop    es
  1679.     ret
  1680.  
  1681. _loadirqvector    endp
  1682. ;
  1683. endif    ; MISC2OBJ
  1684. if MISC2OBJ
  1685. ;
  1686. ;---------------------------====< OurIntVector >====---------------------------
  1687. ;
  1688. ; OurIntVector    -- process DMA interrupts
  1689. ;
  1690.  
  1691. intsemaphore    db    -1        ; -1 free, 0+ locked
  1692.  
  1693.     public    OurIntVector
  1694. OurIntVector    proc
  1695.     push    dx
  1696.     push    ax
  1697.         push    ds
  1698.  
  1699. if MODELSIZE eq 0
  1700.     mov    ax,cs            ; tiny (.com) model uses cs segment
  1701. else
  1702.     mov    ax,@data        ; all others use their data segments
  1703. endif
  1704.     mov    ds,ax
  1705.  
  1706.     mov    dx,INTRCTLRST        ; clear the interrupt
  1707.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1708.     in    al,dx
  1709.  
  1710.         test    al,bISsampbuff          ; our interrupt?
  1711.     jz    skip_int        ; no, continue on...
  1712.  
  1713.     out    dx,al            ; yes, flush it...
  1714.  
  1715.     mov    al,EOI            ; clear the interrupt
  1716.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1717.     jb    @F
  1718.     out    IRQ2ACKREG,al
  1719.     ;
  1720.     @@:
  1721.     out    IRQ1ACKREG,al
  1722.  
  1723.         inc     [NumberOfInterrupts]
  1724.  
  1725.     inc    cs:[intsemaphore]
  1726.         jnz     oiv_done
  1727.  
  1728.     sti                ; let interrupts go while we work
  1729.  
  1730.     cmp    wptr [UserRoutine+2],0    ; call the user function?
  1731.     jz    oiv_done        ; no, just exit
  1732.  
  1733.     call    dword ptr [UserRoutine]
  1734. ;
  1735. oiv_done:
  1736.     dec    cs:[intsemaphore]
  1737. ;
  1738. exit_int:
  1739.     pop    ds
  1740.     pop    ax
  1741.     pop    dx
  1742.     iret
  1743. ;
  1744. skip_int:
  1745.     pushf
  1746.     call    dword ptr ds:[OldIRQRoutine] ; perform the old interrupt
  1747.     jmp    short exit_int
  1748.  
  1749. OurIntVector    endp
  1750. ;
  1751. endif    ; MISC2OBJ
  1752. if PCMOBJ
  1753. ;
  1754. ;---------------------------====< SetupPCMDMAIO >====--------------------------
  1755. ;
  1756. ; SetupPCMDMAIO  --  Setup to output to the DAC
  1757. ;
  1758.     public    SetupPCMDMAIO
  1759. SetupPCMDMAIO   proc
  1760.     push    es
  1761.     push    di
  1762.     les    di,[mvhwShadowPointer]
  1763. ;
  1764. ; setup the sample rate timer
  1765. ;
  1766.         call    _ASloadtimer0
  1767. ;
  1768. ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
  1769. ;
  1770.         mov     ax,[DMABuffLength]      ; get the count
  1771.     sub    dx,dx
  1772.     add    ax,1            ; make it 1 based (1 - 64k)
  1773.     adc    dx,dx
  1774.     mov    cl,[DMABUffDivides]    ; get the buffer size
  1775.     sub    ch,ch
  1776.     div    cx            ; now, we must be flexible
  1777.  
  1778.     mov    bl,[TheDMAChannel]    ; is this a 16 bit channel?
  1779.     mov    bh,[SampleSize]     ; CX = sample size, channel
  1780.  
  1781.     sub    cx,cx            ; ch = multiplier, cl=divider
  1782.     cmp    bx,0003h        ; 8 bits on 8 bit channel?
  1783.     jbe    @F            ; yes, continue on...
  1784.  
  1785.     inc    cx            ; divide by 2
  1786.     cmp    bx,0007h        ; 8 bits on 16 bit channel?
  1787.     jbe    @F            ; yes, continue on...
  1788.  
  1789.     xchg    ch,cl            ; multiply by 2
  1790.     cmp    bx,0203h        ; 16 bits on 8 bit channel?
  1791.     jbe    @F            ; yes, continue on...
  1792.     sub    cx,cx            ; no multiply or divide
  1793.     ;
  1794.     @@:
  1795.         shr     ax,cl                   ; if 8 on 16 divide by 2
  1796.     xchg    ch,cl
  1797.     shl    ax,cl            ; if 16 on 8 multiply by 2
  1798.  
  1799.     sub    cx,cx            ; The buffer size is # of bytes, so
  1800.     neg    bh            ; we must convert it to the data size
  1801.     adc    cx,cx
  1802.     shr    ax,cl
  1803.  
  1804.         call    FFAR ptr _ASloadtimer1
  1805. ;
  1806. ; Setup the system interrupt mask (IRQ mask)
  1807. ;
  1808.     mov    dx,IRQ1MASKREG
  1809.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1810.     jl    @F
  1811.     mov    dl,IRQ2MASKREG
  1812.     ;
  1813.     @@:
  1814.     in    al,dx            ; get the mask
  1815.     mov    ah,TheIRQMask
  1816.     not    ah
  1817.     and    al,ah            ; unmask the correct IRQ
  1818.     out    dx,al            ; then let the system know
  1819. ;
  1820. ; Setup the Interrupt Control Register
  1821. ;
  1822.     mov    dx,INTRCTLRST        ; flush any pending interrupts
  1823.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1824.     out    dx,al            ; of the PCM circuitry
  1825.  
  1826.         mov     dx,INTRCTLR
  1827.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1828.     in    al,dx            ; get the real mask
  1829.     or    al,bICsampbuff        ; interrupt on sample buffer count
  1830.     out    dx,al            ; send it..
  1831.     mov    es:[di._intrctlr],al    ; save it..
  1832. ;
  1833. ; enable the 12/16 bit stuff
  1834. ;
  1835.     test    [_MVHWVersionBits],bMV101 ; 101 chip?
  1836.     jz    sdhpas1_05          ; no, don't touch this...
  1837.  
  1838.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
  1839.     cmp    [SampleSize],1        ; 12 bit?
  1840.     jz    @F
  1841.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
  1842.     cmp    [SampleSize],2        ; 16 bit?
  1843.     jz    @F
  1844.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + 0
  1845.     ;
  1846.     @@:
  1847.     mov    dx,SYSCONFIG2
  1848.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1849.     in    al,dx
  1850.     and    al,ch            ; clear the bits
  1851.     or    al,cl            ; set the appropriate bits
  1852.     out    dx,al
  1853.     ;
  1854.     sdhpas1_05:
  1855. ;
  1856. ; setup the direction, stereo/mono and DMA enable bits
  1857. ;
  1858.     mov    al,bCCmono        ; get the stereo/mono mask bit
  1859.     and    al,[StereoMono]     ; al = bCCmono if in mono mode
  1860.     or    al,[PCMDirection]    ; get the direction bit mask
  1861.     or    al,bCCenapcm        ; enable the PCM state machine
  1862.         mov     dx,CROSSCHANNEL
  1863.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1864.     mov    ah,0fh + bCCdrq     ; get a mask to load non PCM bits
  1865.     and    ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
  1866.     or    al,ah            ; merge the two states
  1867.     xor    al,bCCenapcm        ; disable the PCM bit
  1868.     out    dx,al            ; send to the hardware
  1869.     xor    al,bCCenapcm        ; enable the PCM bit
  1870.     out    dx,al            ; send to the hardware
  1871.     mov    es:[di._crosschannel],al; and save the new state
  1872. ;
  1873. ; Setup the audio filter sample bits
  1874. ;
  1875.     mov    al,es:[di._audiofilt]
  1876.     or    al,(bFIsrate+bFIsbuff)    ; enable the sample count/buff counters
  1877.     mov    dx,AUDIOFILT
  1878.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1879.     out    dx,al
  1880.     mov    es:[di._audiofilt],al
  1881.  
  1882.         mov     NumberOfInterrupts,0
  1883.  
  1884.         enable                          ; Fly, baby Fly!!!
  1885.  
  1886.     pop    di
  1887.     pop    es
  1888.     ret
  1889.  
  1890. SetupPCMDMAIO    endp
  1891. ;
  1892. ;
  1893. ;---------------------------====< SetupPCMPolledIO >====-----------------------
  1894. ;
  1895. ; SetupPCMPolledIO  --    Setup to read/write to the ADC/DAC in a polled fashion
  1896. ;
  1897.     public    SetupPCMPolledIO
  1898. SetupPCMPolledIO        proc
  1899.     push    es
  1900.     push    di
  1901.     les    di,[mvhwShadowPointer]
  1902. ;
  1903. ; Setup the Sample Timer (T0 & square wave output)
  1904. ;
  1905.     call    _ASloadTimer0
  1906. ;
  1907. ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
  1908. ;
  1909.     mov    ax,1            ; get the count
  1910.     call    FFAR ptr _ASloadtimer1
  1911. ;
  1912. ; Setup the Interrupt Control Register
  1913. ;
  1914.         mov     dx,INTRCTLR
  1915.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  1916.     in    al,dx               ; get the real mask
  1917.     or    al,bICsampbuff+bICsamprate ; enable both sample timer ints
  1918.     out    dx,al               ; send it...
  1919.     mov    es:[di._intrctlr],al       ; save it...
  1920. ;
  1921. ; enable the 16 bit stuff
  1922. ;
  1923.     test    [_MVHWVersionBits],bMV101 ; 101 chip?
  1924.     jz    sphpas1_05          ; no, don't touch this...
  1925.  
  1926.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
  1927.     cmp    [SampleSize],1        ; 12 bit?
  1928.     jz    @F
  1929.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
  1930.     cmp    [SampleSize],2        ; 16 bit?
  1931.     jz    @F
  1932.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + 0
  1933.     ;
  1934.     @@:
  1935.     mov    dx,SYSCONFIG2
  1936.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1937.     in    al,dx
  1938.     and    al,ch            ; clear the bits
  1939.     or    al,cl            ; set the appropriate bits
  1940.     out    dx,al
  1941.     ;
  1942.     sphpas1_05:
  1943. ;
  1944. ; setup the direction, stereo/mono and DMA enable bits
  1945. ;
  1946.     mov    al,bCCmono        ; get the stereo/mono mask bit
  1947.     and    al,[StereoMono]     ; al = bCCmono if in mono mode
  1948.     or    al,[PCMDirection]    ; get the direction bit mask
  1949.     or    al,bCCenapcm + bCCdrq    ; enable the PCM & set DRQ for NOT mask
  1950.         mov     dx,CROSSCHANNEL
  1951.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1952.     mov    ah,0fh            ; get a mask to load the non-PCM bits
  1953.     and    ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
  1954.     or    al,ah            ; merge the two states
  1955.     xor    al,bCCenapcm + bCCdrq    ; disable the PCM & DRQ
  1956.     out    dx,al            ; send to the hardware
  1957.     xor    al,bCCenapcm        ; enable the PCM
  1958.     out    dx,al
  1959.     mov    es:[di._crosschannel],al; and save the new state
  1960. ;
  1961. ; Setup the audio filter sample bits to enable sample timer/count
  1962. ;
  1963.     mov    al,es:[di._audiofilt]
  1964.     or    al,(bFIsrate+bFIsbuff)    ; enable the sample timer/counter
  1965.     mov    dx,AUDIOFILT
  1966.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1967.     out    dx,al
  1968.     mov    es:[di._audiofilt],al
  1969.  
  1970.         sub     ax,ax
  1971.     mov    NumberOfInterrupts,ax
  1972.  
  1973.         enable
  1974.  
  1975.     pop    di
  1976.     pop    es
  1977.     ret
  1978.  
  1979. SetupPCMPolledIO   endp
  1980. ;
  1981. ;
  1982. ;----------------------------====< StartPlaying >====--------------------------
  1983. ;
  1984.     public    StartPlaying
  1985. StartPlaying    proc
  1986. ;
  1987. ; Save the type of setup. It contains the interrupt masks needed
  1988. ;
  1989.     mov    [TypeOfSetup],DMAOUTPUT
  1990.     mov    [PCMDirection],bCCdac    ; bit d6 of interrupt control register
  1991. ;
  1992. ; Select the DMA mode for playing
  1993. ;
  1994.     mov    al,10h            ; auto init bit on 8237 chip
  1995.     and    al,[DMAAutoInit]    ; al may have the auto-init bit
  1996.     or    al,48h            ; merge in the rest of the DMA bits
  1997.     mov    TheDMAMode,al        ; save the mode
  1998. ;
  1999. ; Program the DMA, then our board circuitry to start the interrupts
  2000. ;
  2001.         call    LoadDMA                 ; setup the DMA controller
  2002.     call    SetupPCMDMAIO        ; Setup the MV Hardware
  2003.  
  2004.     mov    StatusWord,1        ; set the global status word
  2005.  
  2006.         ret
  2007.  
  2008. StartPlaying    endp
  2009. ;
  2010. ;
  2011. ;---------------------------====< StartRecording >====-------------------------
  2012. ;
  2013.     public    StartRecording
  2014. StartRecording    proc
  2015. ;
  2016. ; Save the type of setup. It contains the interrupt masks needed
  2017. ;
  2018.     mov    [TypeOfSetup],DMAINPUT
  2019.     mov    [PCMDirection],00h    ; bit d6 of interrupt control register
  2020. ;
  2021. ; Select the DMA mode for recording
  2022. ;
  2023.     mov    al,10h            ; auto init bit on 8237 chip
  2024.     and    al,[DMAAutoInit]    ; al may have the auto-init bit
  2025.     or    al,44h            ; merge in the rest of the DMA bits
  2026.     mov    TheDMAMode,al        ; save the mode
  2027. ;
  2028. ; Program the DMA, then our board circuitry to start the interrupts
  2029. ;
  2030.         call    LoadDMA                 ; setup the DMA controller
  2031.     call    SetupPCMDMAIO        ; Setup the MV Hardware
  2032.  
  2033.     mov    StatusWord,2        ; set the global status word
  2034.         ret
  2035.  
  2036. StartRecording    endp
  2037. ;
  2038. endif    ; PCMOBJ
  2039. if MISC2OBJ
  2040. ;
  2041. ;---------------------====< _unloadirqvector >====---------------
  2042. ;
  2043. ; Restore the original vector
  2044. ;
  2045. ; Entry Conditions:
  2046. ;     dParm1 points to the user routine
  2047. ;
  2048. ; Exit Conditions:
  2049. ;     Nothing
  2050. ;
  2051. ;
  2052.     public    _unloadirqvector
  2053. _unloadirqvector    proc
  2054.     push    es
  2055.  
  2056.         les     ax,OldIRQRoutine
  2057.     mov    bx,es
  2058.     or    bx,ax
  2059.     jz    @F
  2060.  
  2061.     mov    bl,[TheIRQChannel]
  2062.     call    _getirqoffset
  2063.  
  2064.     push    ds
  2065.     sub    cx,cx
  2066.     mov    ds,cx
  2067.  
  2068.         disable
  2069.     mov    ds:[bx+0],ax
  2070.     mov    ds:[bx+2],es
  2071.         enable
  2072.  
  2073.     pop    ds
  2074.  
  2075.         sub     ax,ax
  2076.     mov    wptr [OldIRQRoutine+0],ax
  2077.     mov    wptr [OldIRQRoutine+2],ax
  2078. ;
  2079. @@:
  2080.     pop    es
  2081.     ret
  2082.  
  2083. _unloadirqvector    endp
  2084.  
  2085. endif    ; MISC2OBJ
  2086.  
  2087.     end
  2088.  
  2089.